﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Spore.Utils
{
    public class FormaterForBaseType
    {
        private static Type type_Int32 = typeof(Int32);
        private static Type type_UInt32 = typeof(UInt32);
        private static Type type_Int16 = typeof(Int16);
        private static Type type_UInt16 = typeof(UInt16);
        private static Type type_Float = typeof(float);
        private static Type type_Long = typeof(long);
        private static Type type_Double = typeof(Double);
        private static Type type_ULonge = typeof(ulong);
        private static Type type_Char = typeof(Char);
        private static Type type_Byte = typeof(byte);
        private static Type type_Time = typeof(DateTime);
        private static Type type_decimal = typeof(decimal);
        private static Type type_IntPtr = typeof(IntPtr);
        private static Type type_string = typeof(string);
        private static Type type_object = typeof(object);
        private static Type type_Bool = typeof(bool);
       

       private static List<Type> baseTypes = new List<Type>();
      
        static  FormaterForBaseType()
       {
           baseTypes.Add(type_UInt32);
           baseTypes.Add(type_ULonge);
           baseTypes.Add(type_UInt16);
           baseTypes.Add(type_Time);
           baseTypes.Add(type_string);
           baseTypes.Add(type_Long);
           baseTypes.Add(type_IntPtr);
           baseTypes.Add(type_Int32);
           baseTypes.Add(type_Int16);
           baseTypes.Add(type_Float);
           baseTypes.Add(type_Double);
           baseTypes.Add(type_decimal);
           baseTypes.Add(type_Char);
           baseTypes.Add(type_Byte);
       }

        //  //可空类型类型处理
        //if (conversionType.IsGenericType &&
        //        conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
        //{
        //    if (value == null)
        //        return null;
 
        //    System.ComponentModel.NullableConverter nullableConverter
        //        = new System.ComponentModel.NullableConverter(conversionType);
 
        //    conversionType = nullableConverter.UnderlyingType;
        //}
 
        //return Convert.ChangeType(value, conversionType);

        public static bool IsBaseType(Type type)
        {
            if (type.IsEnum) return true;
            if (baseTypes.Contains(type))
                return true;
            return false;
        }

        #region formate
        public static byte[] FormateBaseType(object obj)
        {
            Type type = obj.GetType();
            if (type.IsEnum)
            {
                obj = Convert.ChangeType(obj, Enum.GetUnderlyingType(type));
                return FormateBaseType(obj);
            }
            if (type == type_object)
            {
                if (obj == null)
                    return new byte[]{0};
                else
                    return  new byte[]{1};
            }
            if (type == type_Bool)
            {
                bool temp =( bool)obj;
                return new byte[]{(byte)(temp?1:0)};
            }
            if (type == type_Byte)
            {
                return new byte[] { (byte)obj };
            }
            else if (type== type_Char)
            {
                return BitConverter.GetBytes((char)obj);
            }
            else if (type == type_Double || type == type_decimal)
            {
                return BitConverter.GetBytes((double)obj);
            }
            else if (type == type_Float)
            {
                return BitConverter.GetBytes((float)obj);
            }
            else if (type == type_Int16)
            {
                return BitConverter.GetBytes((Int16)obj);
            }
            else if (type == type_Int32)
            {
                return BitConverter.GetBytes((Int32)obj);
            }
            else if (type == type_IntPtr)
            {
                return BitConverter.GetBytes(((IntPtr)(obj)).ToInt32());
            }
            else if (type == type_Long)
            {
                return BitConverter.GetBytes((long)obj);
            }
            else if (type == type_string)
            {
                string data = obj as string;
                if(data==null)
                    return BitConverter.GetBytes((int)-1);
                if (data == string.Empty)
                {
                    return new byte[4];
                }
                byte[] ret = FormateString(data);
                return ret;
            }
            else if (type == type_Time)
            {
                DateTime dt = (DateTime)obj;
                return FormatDateTime(ref dt);
            }
            throw new ArgumentException("不被支持的基本类型！");
        }

        public static byte[] FormateString(string data)
        {
            byte[] temp = Encoding.Default.GetBytes(data);
            byte[] length = BitConverter.GetBytes(temp.Length);
            byte[] ret = new byte[temp.Length + length.Length];
            Array.Copy(length, 0, ret, 0, length.Length);
            Array.Copy(temp, 0, ret, length.Length, temp.Length);
            return ret;
        }

        public static byte[] FormatDateTime(ref DateTime dt)
        {
            BitArray year = new BitArray(BitConverter.GetBytes(dt.Year));
            BitArray month = new BitArray(new byte[] { ((Byte)dt.Month) });
            BitArray day = new BitArray(new byte[] { ((Byte)dt.Day) });
            BitArray hour = new BitArray(new byte[] { (byte)dt.Hour });
            BitArray minute = new BitArray(new byte[] { (byte)dt.Minute });
            BitArray second = new BitArray(new byte[] { (byte)dt.Second });
            BitArray bits = new BitArray(40);
            for (int i = 0; i < 13; i++)
            {
                bits[i] = year[i];
                Console.Write(bits[i].ToString() + " ");
            }
            Console.WriteLine();
            for (int i = 0; i < 4; i++)
            {
                bits[13 + i] = month[i];
            }
            for (int i = 0; i < 5; i++)
            {
                bits[17 + i] = day[i];
                bits[22 + i] = hour[i];
                bits[27 + i] = minute[i];
                bits[33 + i] = second[i];
            }
            bits[32] = minute[5];
            bits[38] = second[5];
            byte[] ret = new byte[5];
            for (int i = 0; i < bits.Length; i++)
            {
                ret[i / 8] |= ((byte)((bits[i] ? 1 : 0) <<(i % 8)));
            }
            return ret;
        }

        public static byte[] FormateArrayBaseType(object obj)
        {
            Array ay = (Array)obj;
            if(ay.Rank>1)
                throw new ArgumentException("不支持多维数据的格式化");
            if (ay == null)
                return new byte[4];
            byte[] length = BitConverter.GetBytes(ay.Length);
            List<byte> ret = new List<byte>();
            ret.AddRange(length);
            foreach (var v in ay)
            {
                byte[] temp = FormateBaseType(v);
                length = BitConverter.GetBytes((UInt16)temp.Length);
                ret.AddRange(length);
                ret.AddRange(temp);
            }
            return ret.ToArray();
        }
        #endregion

        public static object DeFormateBaseObj(Type type,byte[] data, int startIndex,out int length)
        {
            length = 4;
            if (type.IsEnum)
            {
                Type baseType = Enum.GetUnderlyingType(type);
                object obj = DeFormateBaseObj(baseType, data, startIndex, out length);
                return Enum.Parse(type, obj.ToString());
            }
            if (type == type_object)
            {
                length = 1;
                if (data[startIndex] == 0) return null;
                return new object();
            }
            else if (type == type_Bool)
            {
                length = 1;
                return data[startIndex] == 1;
            }
            else if (type == type_Byte)
            {
                length = 1;
                return data[startIndex];
            }
            else if (type == type_Char)
            {
                length = 2;
                return BitConverter.ToChar(data, startIndex);
            }
            else if (type == type_decimal)
            {
                length =8;
                return BitConverter.ToDouble(data, startIndex);
                //BitConverter.GetBytes(
            }
            else if (type == type_Double)
            {
                length = 8;
                return BitConverter.ToDouble(data, startIndex);
            }
            else if (type == type_Float)
            {
                length = 4;
                return BitConverter.ToSingle(data, startIndex);
            }
            else if (type == type_Int16)
            {
                length = 2;
                return BitConverter.ToInt16(data, startIndex);
            }
            else if (type == type_Int32)
            {
                length = 4;
                return BitConverter.ToInt32(data, startIndex);
            }
            else if (type == type_IntPtr)
            {
                length = 4;
                return new IntPtr(BitConverter.ToInt32(data, startIndex));
            }
            else if (type == type_Long)
            {
                length = 8;
                return BitConverter.ToInt64(data, startIndex);
            }
            else if (type == type_UInt16)
            {
                length = 2;
                return BitConverter.ToUInt16(data, startIndex);
            }
            else if (type == type_UInt32)
            {
                length = 4;
                return BitConverter.ToUInt32(data, startIndex);
            }
            else if (type == type_ULonge)
            {
                length = 8;
                return BitConverter.ToUInt64(data, startIndex);
            }
            else if (type == type_string)
            {
                return DeformateString(data, startIndex, out length);
            }
            else if (type == type_Time)
            {
                length = 5;
                return DeformateDateTime(data, startIndex);
            }
            else
            {
                throw new ArgumentException("该类型未不支持反格式化！");
            }
            
            
        }

        public static string DeformateString(byte[] data, int startIndex, out int length)
        {
            length = 4;
            int temp  = BitConverter.ToInt32(data, startIndex);
            if (temp == 0) return string.Empty;
            if (temp == -1) return null;
            length = temp+4;
            return new string(Encoding.Default.GetChars(data, startIndex + 4, temp));
        }

        public static DateTime DeformateDateTime(byte[] data, int startIndex)
        {
            byte[] temp = new byte[5];
            Array.Copy(data, startIndex, temp, 0, 5);
            BitArray bits = new BitArray(temp);
            int year = 0;
            int month = 0;
            int day = 0;
            int hour = 0;
            int minute = 0;
            int second = 0;
            for (int i = 0; i < 13; i++)
            {
                year |= ((bits[i] ? 1 : 0) << (i));
            }
            for (int i = 0; i < 4; i++)
            {
                month |= ((bits[13 + i] ? 1 : 0) << (i));
                day |= ((bits[17 + i] ? 1 : 0) << (i));
                hour |= ((bits[22 + i] ? 1 : 0) << (i));
                minute |= ((bits[27 + i] ? 1 : 0) << (i));
                second |= ((bits[33 + i] ? 1 : 0) << (i));
            }
            day |= ((bits[21] ? 1 : 0) << 4);
            hour |= ((bits[26] ? 1 : 0) << 4);
            minute |= (bits[31] ? 1 : 0) << 4;
            minute |= (bits[32] ? 1 : 0) << 5;
            second |= (bits[37] ? 1 : 0) << 4;
            second |= (bits[38] ? 1 : 0) << 5;
            return new DateTime(year, month, day, hour, minute, second);
        }
        
    }
}
